說到接 API , 大家一定都會使用到的就是地圖相關的服務了吧?而通常這個被用到的服務都是 Google Map。看了一些接 Google Map 的應用教學,老實說,我覺得有點無聊,不想跟別人做一樣的東西。而說到其他知名的地圖服務,大概就是 Mapbox 跟 OpenStreetMap 了,基本上 Mapbox 也是從 OpenStreetMap 衍生出來的一個地圖服務新創。幾年前注意到 Mapbox 這個新創的時候,就對他們 Demo 上的漂亮地圖感到驚豔,所以不管怎樣都想要用用看。
在搜尋 Mapbox 相關的中文教學時,我注意到簡體中文的教學相當多,而台灣本地的繁體教學寥寥無幾,希望這篇簡易教學可以拋磚引玉、增加一點繁體中文的資源。
Mapbox 為人所喜愛的主要原因,就是因為他有個地圖編輯器,讓使用者可以依照自己需求客製化不同樣貌的地圖,選擇想要顯示的元素(公車路線、大樓、道路等)塗上自己喜歡的顏色。
在Mapbox Studio 裡面取得 Access Token
跟管理地圖樣式 (Styles) 跟其他自訂資料:
Create Style 裡面的地圖編輯器:
Mapbox GL JS 是利用 WebGL 技術繪製互動式地圖的 JS Library ,在做出客製化的地圖 Styles 之後,我們就要利用這個 library 來在網頁上呈現地圖。
順帶一提,Mapbox GL JS 跟 Mapbox.js 是兩個不同的 library,前者的地圖是向量,基本上是要取代使用點陣地圖的後者,兩者不相容。在這邊不多贅述兩者差異。
因為這個部分跟 API 的主題比較沒關聯,而是在簡單介紹 Mapbox 跟為後面的 Direction API 做準備,我們直接拿範例來改:
實作如下
// 改自 Mapbox GL JS 的範例
<html>
<head>
<!--在 HTML Head 裡面置入 mapbox-gl.js 跟 mapbox-gl.css -->
<script src='https://api.tiles.mapbox.com/mapbox-gl-js/v0.42.2/mapbox-gl.js'></script>
<link href='https://api.tiles.mapbox.com/mapbox-gl-js/v0.42.2/mapbox-gl.css' rel='stylesheet' />
</head>
<body>
<!--放一個有 id 的 container,等等用 script 載入地圖,要記得指定寬跟高 -->
<div id='map' style='width: 400px; height: 300px;'></div>
<script>
// 在 Mapbox Studio 裡面得到的 Access Token 放在下方
mapboxgl.accessToken = 'pk.eyJ1IjoiY2hyeXNvcGh5dGEiLCJhIjoiY2piZnVhOXFyMnhicjMybnoyOG5ueW43cCJ9.i6e5n-YiCbVQG-dvJAdkQQ';
var map = new mapboxgl.Map({
container: 'map',
// 在 Mapbox Studio 裡面製作的 Style 得到的 Style Url
style: 'mapbox://styles/chrysophyta/cjbfwi7c60m0w2smz9hwekkxv'
});
</script>
</body>
</html>
最後得到了一個復古小地圖
上面做了一個地圖,實在說不上是接了一支 API 吧。所以從 Mapbox 提供的相關服務 API 裡面,挑了一個 Direction API 來試試。我想要使用這個 API 在我剛剛做好的地圖上畫上一個路線圖。
(雖然說,Mapbox GL JS 裡面本來就有 mapbox-gl-directions 的 plugin 可以用,但這邊的目的是練習)
如果覺得看文件感覺有些複雜,不如把 Direction API 的 API Playground 打開來玩一玩,就會覺得清楚許多。
Direction API 的呼叫方法是
'GET', 'https://api.mapbox.com/directions/v5/{profile}/{coordinates}'
如上所述,他的 URL 需要以下參數:
profile
交通模式:有 mapbox/driving-traffic
、 mapbox/driving
、mapbox/walking
、跟 mapbox/cycling
四種可以選
coordinates
座標:是 2 ~ 25 組的 經度,緯度
。經跟緯用逗號(%2C)分開、每組座標以 semi-colon (%3B) 分隔。
還有理所當然的你的 Access Token
此時我們就來寫一個基礎的 XMLHttpRequest 然後將 API Playground 裡面的 Request URL
放進 .open()
裡面
function getDirection() {
var xhr = new XMLHttpRequest();
xhr.open(
"GET",
"https://api.mapbox.com/directions/v5/mapbox/walking/-73.989%2C40.733%3B-74%2C40.733.json?access_token=pk.eyJ1IjoiY2hyeXNvcGh5dGEiLCJhIjoiY2piZnVhOXFyMnhicjMybnoyOG5ueW43cCJ9.i6e5n-YiCbVQG-dvJAdkQQ"
);
xhr.onload = function() {
var response = JSON.parse(this.responseText);
console.log(response);
};
xhr.send();
}
getDirection();
就會得到跟 API Playground 裡面的 Response 一模一樣的 object 。(這不是廢話嗎)
讓我們來研究一下這個 Response 到底在寫什麼。
一個 Direction Response Object 裡面會有三個物件:code
、routes
、waypoints
。
code
基本上會標明這個 request 有沒有成功routes
會給出最多兩組的路線,包含各個步驟的座標跟指示敘述waypoints
會給出路線中的停頓點雖然得到了這些 data,但其實我並不知道我需要哪些來在地圖上畫圖。回去看 GL JS 的文件,裡面有一項是「使用GeoJSON在地圖上畫線」,也就是說我們需要得到 GeoJSON 格式的 data。
而前面呼叫 API 時,有個 geometries=geojson
的參數可以使用,他會傳回 GeoJSON 格式的 response 。
把 geometries=geojson
加上 request URL 之後,來比對一下新的 response 長得跟 「使用GeoJSON在地圖上畫線」範例裡面所需要的 data 是不是很相似:
看起來大部分都挺相似的,畢竟是大家都是自己人(?),Direction API 就是給 GL JS Library 拿去用的嘛。
來實作吧
// Provide your access token
mapboxgl.accessToken =
"pk.eyJ1IjoiY2hyeXNvcGh5dGEiLCJhIjoiY2piZnVhOXFyMnhicjMybnoyOG5ueW43cCJ9.i6e5n-YiCbVQG-dvJAdkQQ";
// Create a map in the div #map
var map = new mapboxgl.Map({
container: "map",
center: [-73.993, 40.733],
style: "mapbox://styles/chrysophyta/cjbfwh87t036h2smvxox647hp",
zoom: 14
});
function getDirection() {
var xhr = new XMLHttpRequest();
xhr.open(
"GET",
"https://api.mapbox.com/directions/v5/mapbox/walking/-73.989%2C40.733%3B-74%2C40.733.json?access_token=pk.eyJ1IjoiY2hyeXNvcGh5dGEiLCJhIjoiY2piZnVhOXFyMnhicjMybnoyOG5ueW43cCJ9.i6e5n-YiCbVQG-dvJAdkQQ&geometries=geojson"
);
xhr.onload = function() {
var response = JSON.parse(this.responseText);
var routeGeometries = response.routes[0].geometry;
//這邊的 code 改自 add a line with GeoJSON 的範例
map.on("load", function() {
map.addLayer({
id: "route",
type: "line",
source: {
type: "geojson",
data: {
type: "Feature",
properties: {},
geometry: {
type: "LineString",
// 把 coordinates 改成從 Direction API 拿回來的座標
coordinates: routeGeometries.coordinates
}
}
},
layout: {
"line-join": "round",
"line-cap": "round"
},
paint: {
"line-color": "#000",
"line-width": 3
}
});
});
};
xhr.send();
}
getDirection();
路線出現了,好感人啊。
今天的 API 教學在此告一段落,Demo 在這邊。
寫得好累。(抹臉)